#include <iostream>
#include <sys/types.h>
#include <pthread.h>
#include <cstdlib>
#include <cerrno>
#include <functional>
#include "sock.hpp"
using std::cout;
using std::endl;
using std::string;

using fun_t = std::function<string(string &)>;

const int g_buffer_size = 1024;

class HttpServer;

class ThreadData
{
public:
    ThreadData(int sock, uint16_t port, HttpServer *hs)
        : sock_(sock), port_(port), hs_(hs)
    {
    }

public:
    int sock_;
    uint16_t port_;
    HttpServer *hs_;
};

class HttpServer
{
public:
    HttpServer(fun_t func, uint16_t port) : port_(port), func_(func)
    {
    }
    void InitServer()
    {
        listen_sock_.Bind(port_);
        listen_sock_.Listen();
    }

    void HttpRequest(int& sock)
    {
        char buffer[g_buffer_size];
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            string request = buffer;
            string response = func_(request);
            send(sock, response.c_str(), response.size(), 0);
        }
        else
        {
            logMessage(Error, "recv error,%d:%s", errno, strerror(errno));
        }
    }

    static void *ThreadRoutine(void *argv)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(argv);
        td->hs_->HttpRequest(td->sock_);

        close(td->sock_);
        delete td;
    }

    void StartServer()
    {
        while (true)
        {
            uint16_t client_port;
            string client_ip;

            int sock = listen_sock_.Accept(&client_ip, &client_port);
            if (sock < 0)
                continue;

            pthread_t tid;

            ThreadData *td = new ThreadData(sock, port_, this);
            pthread_create(&tid, nullptr, ThreadRoutine, (void *)td);
        }
    }

    ~HttpServer()
    {}

private:
    uint16_t port_;
    Sock listen_sock_;
    fun_t func_;
};
